#ifndef STLCOMPAT_SPAN_H
#define STLCOMPAT_SPAN_H

#include <array>
#include <type_traits>
#include <vector>

/**
 * @def KP_HAS_STD_SPAN
 * @brief 检测当前编译环境是否支持 C++20 <span>。
 * @details
 *  仅在标准库报告 `__cpp_lib_span >= 202002L` 时定义，否则为空。
 *  上层代码可通过 `#if KP_HAS_STD_SPAN` 做条件编译，
 *  优先使用 `std::span` 以享受标准库优化与调试支持。
 */
#if defined(__cpp_lib_span) && (__cpp_lib_span >= 202002L)
#define KP_HAS_STD_SPAN
#endif // STLCOMPAT_SPAN_H

#ifndef KP_HAS_STD_SPAN

namespace kp
{
/**
 * @file span.h
 * @brief 为 C++17 之前的环境提供轻量级、零开销的连续内存视图（span）实现。
 *
 * 设计初衷：
 * 1. 兼容 C++20 std::span 的接口，使得迁移到 C++20 时无需改动调用代码。
 * 2. 在编译期即可区分“静态长度”与“动态长度”，从而生成最优代码：
 *    - 静态长度（Extent != dynamic_extent）版本在 size()/size_bytes() 等接口中
 *      直接返回编译期常量，编译器可彻底消除分支与内存访问。
 *    - 动态长度版本保留运行时长度字段，但仍保持与 std::span 一致的 ABI。
 * 3. 所有操作均为 constexpr 且 noexcept，确保可在最严苛的编译期上下文
 *    （如 constexpr 函数、模板元编程）中使用，同时不向运行时抛出异常。
 * 4. 通过 SFINAE 与 static_assert 在编译期拒绝非法构造（如长度不匹配、
 *    非连续迭代器），将错误提前到编译期而非运行时。
 * 5. 提供与 std::array、C 数组、std::vector、迭代器范围等多种数据源的
 *    无缝衔接，减少样板代码。
 *
 * 设计要点：
 * - 采用“指针 + 可选长度”的极简表示，不拥有内存，仅作视图。
 * - 对静态长度实例，省略 size_ 成员，节省内存。
 * - 所有子视图（first/last/subspan）均提供编译期长度与运行时长度双版本，
 *   方便模板元编程与运行时算法共用同一套 API。
 * - 比较运算符仅比较“地址与长度”而非逐元素，保持与 std::span 语义一致，
 *   并允许不同 cv 限定与长度的 span 之间进行相等比较。
 */

/**
 * @def dynamic_extent
 * @brief 用于表示“运行时长度”的哨值。
 *
 * 采用 std::size_t(-1) 保证与 std::span 的 dynamic_extent 值保持一致，
 * 同时避免与任何合法长度冲突。
 */
constexpr std::size_t dynamic_extent = static_cast<std::size_t>(-1);

/**
 * @class span
 * @brief 非拥有型连续内存视图，提供对数组或容器内元素的零开销访问。
 *
 * @tparam T     元素类型，允许 cv 限定符（const / volatile）。
 * @tparam Extent 编译期长度，默认为 dynamic_extent 表示运行时长度。
 *
 * 示例：
 * @code
 * int buf[4] = {1,2,3,4};
 * kp::span<int>      dyn(buf, 4);   // 动态长度
 * kp::span<int,4>    st(buf);       // 静态长度，编译期已知
 * @endcode
 */
template <class T, std::size_t Extent = dynamic_extent>
class span
{
public:
    /**
     * @name 标准类型别名
     *
     * 与 std::span 保持一致，方便泛型代码无需改动即可适配。
     */
    using element_type = T;                                   ///< 元素类型（含 cv 限定）
    using value_type = typename std::remove_cv<T>::type;      ///< 去除 cv 后的元素类型
    using size_type = std::size_t;                            ///< 长度、索引等无符号类型
    using index_type = std::size_t;                           ///< 与 std::span 保持一致
    using difference_type = std::ptrdiff_t;                   ///< 指针差值类型
    using pointer = T *;                                      ///< 可变指针类型
    using const_pointer = const T *;                          ///< 常量指针类型
    using reference = T &;                                    ///< 可变引用类型
    using const_reference = const T &;                        ///< 常量引用类型
    using iterator = pointer;                                 ///< 连续内存迭代器
    using const_iterator = const_pointer;                     ///< 常量迭代器
    using reverse_iterator = std::reverse_iterator<iterator>; ///< 反向迭代器
    using const_reverse_iterator = std::reverse_iterator<const_iterator>; ///< 常量反向迭代器

    /**
     * @brief 编译期长度常量。
     *
     * 当 Extent 为 dynamic_extent 时，该值即为 dynamic_extent；
     * 否则为编译期确定的固定长度，可用于模板元编程。
     */
    static constexpr size_type extent = Extent;

    /**
     * @name 构造函数
     *
     * 所有构造函数均为 constexpr 且 noexcept，确保可在编译期求值。
     * 通过 SFINAE 限制仅对合法参数提供重载，将错误提前到编译期。
     */

    /**
     * @brief 动态长度构造：指针 + 元素个数。
     * @param ptr   连续内存起始地址
     * @param count 元素个数
     * @pre 当 Extent 为静态长度时，该构造函数被禁用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E == dynamic_extent, int>::type = 0>
    constexpr span(pointer ptr, size_type count) noexcept : data_(ptr), size_(count)
    {
    }

    /**
     * @brief 动态长度构造：半开区间 [first, last)。
     * @param first 起始指针
     * @param last  结束指针（不包含）
     * @pre 当 Extent 为静态长度时，该构造函数被禁用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E == dynamic_extent, int>::type = 0>
    constexpr span(pointer first, pointer last) noexcept
        : data_(first), size_(static_cast<size_type>(last - first))
    {
    }

    /**
     * @brief 静态长度构造：仅接受起始指针，长度由编译期常量 Extent 决定。
     * @param ptr 起始地址
     * @pre 当 Extent 为动态长度时，该构造函数被禁用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E != dynamic_extent, int>::type = 0>
    constexpr explicit span(pointer ptr) noexcept : data_(ptr)
    {
    }

    /**
     * @brief 从 C 数组构造。
     * @tparam N 数组长度
     * @param arr 数组引用
     * @pre 若 Extent 为静态长度，则 N 必须与 Extent 相等；否则允许任何长度。
     */
    template <std::size_t N,
              std::size_t E = Extent,
              typename std::enable_if<E == dynamic_extent || E == N, int>::type = 0>
    constexpr span(element_type (&arr)[N]) noexcept : data_(arr), size_(N)
    {
    }

    /**
     * @brief 从 std::array 构造（非 const）。
     * @tparam U  std::array 的元素类型，需与 T 可转换
     * @tparam N 数组长度
     * @param a  数组实例
     * @pre 若 Extent 为静态长度，则 N 必须与 Extent 相等。
     */
    template <class U,
              std::size_t N,
              class = typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value &&
                                              (Extent == dynamic_extent || Extent == N)>::type>
    constexpr span(std::array<U, N> & a) noexcept : data_(a.data()), size_(N)
    {
    }

    /**
     * @brief 从 const std::array 构造。
     * @tparam U  std::array 的元素类型，需与 T 可转换
     * @tparam N 数组长度
     * @param a  数组实例
     * @pre 若 Extent 为静态长度，则 N 必须与 Extent 相等。
     */
    template <class U,
              std::size_t N,
              class = typename std::enable_if<std::is_convertible<const U (*)[], T (*)[]>::value &&
                                              (Extent == dynamic_extent || Extent == N)>::type>
    constexpr span(const std::array<U, N> & a) noexcept : data_(a.data()), size_(N)
    {
    }

    /**
     * @brief 从另一个 span 构造，允许元素类型转换及长度转换。
     * @tparam U   源 span 的元素类型
     * @tparam E   源 span 的长度
     * @param other 源 span
     * @pre 需满足 U(*)[] 可转换为 T(*)[]，且若 Extent 为静态长度，则 E 必须等于 Extent。
     */
    template <class U,
              std::size_t E,
              class = typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value &&
                                              (Extent == dynamic_extent || Extent == E)>::type>
    constexpr span(const span<U, E> & other) noexcept : data_(other.data()), size_(other.size())
    {
    }

    /**
     * @brief 默认构造。
     *
     * 对动态长度实例，数据指针为空，长度为 0；
     * 对静态长度实例，数据指针为空，长度仍为 Extent（但解引用未定义）。
     */
    constexpr span() noexcept : data_(nullptr), size_(Extent == dynamic_extent ? 0 : Extent) {}

    /**
     * @brief 单元素构造。
     * @param element 单个元素的引用
     * @pre 动态长度版本始终可用；静态长度版本仅当 Extent == 1 时可用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E == dynamic_extent, int>::type = 0>
    constexpr explicit span(reference element) noexcept : data_(&element), size_(1)
    {
    }

    template <std::size_t E = Extent,
              typename std::enable_if<E != dynamic_extent && E == 1, int>::type = 0>
    constexpr explicit span(reference element) noexcept : data_(&element)
    {
    }

    /**
     * @brief 重新绑定视图（动态长度）。
     * @param starting_element 新的起始地址
     * @param count            新的元素个数
     * @pre 仅对动态长度实例可用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E == dynamic_extent, int>::type = 0>
    constexpr void reinit(pointer starting_element, size_type count) noexcept
    {
        data_ = starting_element;
        size_ = count;
    }

    /**
     * @brief 重新绑定视图（静态长度）。
     * @param starting_element 新的起始地址
     * @pre 仅对静态长度实例可用。
     */
    template <std::size_t E = Extent, typename std::enable_if<E != dynamic_extent, int>::type = 0>
    constexpr void reinit(pointer starting_element) noexcept
    {
        data_ = starting_element;
    }

    /**
     * @name 容量与属性观察器
     */
    /**
     * @brief 返回元素个数。
     * @return 对静态长度实例返回编译期常量 Extent；对动态长度实例返回运行时长度。
     */
    constexpr size_type size() const noexcept { return Extent == dynamic_extent ? size_ : Extent; }

    /**
     * @brief 是否为空。
     * @return size() == 0
     */
    constexpr bool empty() const noexcept { return size() == 0; }

    /**
     * @brief 返回起始指针。
     * @return 指向连续内存首元素的指针
     */
    constexpr pointer data() const noexcept { return data_; }

    /**
     * @brief 返回占用的字节数。
     * @return size() * sizeof(element_type)
     */
    constexpr size_type size_bytes() const noexcept { return size() * sizeof(element_type); }

    /**
     * @name 迭代器
     *
     * 所有迭代器均为 constexpr 且 noexcept，与指针语义一致。
     */
    constexpr iterator begin() const noexcept { return data_; }
    constexpr iterator end() const noexcept { return data_ + size(); }
    constexpr const_iterator cbegin() const noexcept { return data_; }
    constexpr const_iterator cend() const noexcept { return data_ + size(); }
    constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator(end()); }
    constexpr reverse_iterator rend() const noexcept { return reverse_iterator(begin()); }
    constexpr const_reverse_iterator crbegin() const noexcept
    {
        return const_reverse_iterator(cend());
    }
    constexpr const_reverse_iterator crend() const noexcept
    {
        return const_reverse_iterator(cbegin());
    }

    /**
     * @name 元素访问
     *
     * 不提供边界检查，与 std::span 保持一致。若需安全访问，请在外部确保索引合法。
     */
    constexpr reference operator[](size_type i) const noexcept { return data_[i]; }
    constexpr reference front() const noexcept { return data_[0]; }
    constexpr reference back() const noexcept { return data_[size() - 1]; }

    /**
     * @name 子视图
     *
     * 提供编译期长度与运行时长度双版本，方便模板元编程与运行时算法共用同一套 API。
     */

    /**
     * @brief 获取前 Count 个元素的子视图（编译期长度）。
     * @tparam Count 子视图长度
     * @return span<T, Count>
     * @pre 若 Extent 为静态长度，则 Count <= Extent。
     */
    template <std::size_t Count>
    constexpr auto first() const noexcept -> span<T, Count>
    {
        static_assert(Extent == dynamic_extent || Count <= Extent, "first() Count out of range");
        return span<T, Count>(data_);
    }

    /**
     * @brief 获取前 count 个元素的子视图（运行时长度）。
     * @param count 子视图长度
     * @return span<T, dynamic_extent>
     */
    constexpr span<T, dynamic_extent> first(size_type count) const noexcept
    {
        return span<T, dynamic_extent>(data_, count);
    }

    /**
     * @brief 获取后 Count 个元素的子视图（编译期长度）。
     * @tparam Count 子视图长度
     * @return span<T, Count>
     * @pre 若 Extent 为静态长度，则 Count <= Extent。
     */
    template <std::size_t Count>
    constexpr auto last() const noexcept -> span<T, Count>
    {
        static_assert(Extent == dynamic_extent || Count <= Extent, "last() Count out of range");
        return span<T, Count>(data_ + (size() - Count));
    }

    /**
     * @brief 获取后 count 个元素的子视图（运行时长度）。
     * @param count 子视图长度
     * @return span<T, dynamic_extent>
     */
    constexpr span<T, dynamic_extent> last(size_type count) const noexcept
    {
        return span<T, dynamic_extent>(data_ + (size() - count), count);
    }

    /**
     * @brief 获取从 Offset 开始的子视图（编译期长度与可选编译期长度）。
     * @tparam Offset 起始偏移
     * @tparam Count  子视图长度，默认为 dynamic_extent 表示到末尾
     * @return 新 span 的类型长度由编译期推导
     * @pre 若 Extent 为静态长度，则 Offset + Count <= Extent（若 Count 非 dynamic_extent）。
     */
    template <std::size_t Offset, std::size_t Count = dynamic_extent>
    constexpr auto subspan() const noexcept
        -> span<T,
                (Count != dynamic_extent
                     ? Count
                     : (Extent == dynamic_extent ? dynamic_extent : (Extent - Offset)))>
    {
        constexpr std::size_t newExtent =
            (Count != dynamic_extent)
                ? Count
                : (Extent == dynamic_extent ? dynamic_extent : (Extent - Offset));
        (void)newExtent; // 仅为可读性
        if constexpr (Extent == dynamic_extent)
        {
            return span<T, (Count != dynamic_extent ? Count : dynamic_extent)>(
                data_ + Offset, (Count == dynamic_extent ? size() - Offset : Count));
        }
        else
        {
            return span<T, (Count != dynamic_extent ? Count : (Extent - Offset))>(data_ + Offset);
        }
    }

    /**
     * @brief 获取从 offset 开始的子视图（运行时长度）。
     * @param offset 起始偏移
     * @param count  子视图长度，默认为 dynamic_extent 表示到末尾
     * @return span<T, dynamic_extent>
     */
    constexpr span<T, dynamic_extent> subspan(size_type offset,
                                              size_type count = dynamic_extent) const noexcept
    {
        const size_type n = (count == dynamic_extent) ? (size() - offset) : count;
        return span<T, dynamic_extent>(data_ + offset, n);
    }

    /**
     * @brief 与另一个 span 交换视图。
     * @param other 另一个 span
     * @note 对所有长度均 noexcept，因为仅交换指针与长度。
     */
    constexpr void swap(span & other) noexcept
    {
        auto tmp_ptr = other.data_;
        auto tmp_size = other.size_;
        other.data_ = data_;
        other.size_ = size_;
        data_ = tmp_ptr;
        size_ = tmp_size;
    }

    /**
     * @name 比较运算符
     *
     * 仅比较“地址与长度”而非逐元素，与 std::span 语义一致。
     * 允许不同 cv 限定与长度的 span 之间进行相等比较。
     */

    template <class U,
              std::size_t E,
              class = typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value &&
                                              (Extent == dynamic_extent || Extent == E)>::type>
    constexpr bool operator==(const span<U, E> & other) const noexcept
    {
        return (static_cast<const void *>(data_) == static_cast<const void *>(other.data())) &&
               (size() == other.size());
    }

    template <class U,
              std::size_t E,
              class = typename std::enable_if<std::is_convertible<U (*)[], T (*)[]>::value &&
                                              (Extent == dynamic_extent || Extent == E)>::type>
    constexpr bool operator!=(const span<U, E> & other) const noexcept
    {
        return !(*this == other);
    }

private:
    pointer data_; ///< 指向连续内存首元素的指针
    size_type size_{Extent == dynamic_extent ? 0 : Extent}; ///< 仅对动态长度实例有效
};

namespace internal
{
/**
 * 返回在给定迭代器范围内解引用得到的对象是否在内存中连续排列。
 */
template <class Iterator>
bool
is_contiguous(const Iterator & first, const Iterator & last)
{
    const auto n = std::distance(first, last);
    for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
        if (std::addressof(*(std::next(first, i))) != std::next(std::addressof(*first), i))
            return false;
    return true;
}

/**
 * 返回在给定迭代器范围内解引用得到的对象是否在内存中连续排列。
 *
 * 此特化版本针对（@p const 或非 @p const）指针，无条件返回 @p true，
 * 因为指针所指向的对象在内存中是连续的，这是 C++ 内存模型所保证的。
 */
template <class T>
constexpr bool
is_contiguous(T *, T *)
{
    return true;
}
} // namespace internal

/**
 * 根据一对迭代器创建 span。span 的类型由迭代器的值类型推断
 *（例如，由两个 const 迭代器创建的视图其类型为 const）。
 *
 * @warning 迭代器 @p begin 与 @p end 必须（按通常的半开区间方式）界定一段
 * 内存连续的取值范围。本函数预期用于
 * <code>boost::container::small_vector</code> 或 <code>std::vector</code>
 * 这类容器的迭代器，对于
 * <code>boost::container::stable_vector</code> 或 <code>std::deque</code>
 * 等容器将无法正确工作。在调试模式下，会检查所提供的迭代器是否确实代表连续内存。
 *
 * @relatesalso span
 */
template <typename Iterator>
span<typename std::remove_reference<typename std::iterator_traits<Iterator>::reference>::type>
make_array_view(const Iterator begin, const Iterator end)
{
    static_assert(std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
                               typename std::random_access_iterator_tag>::value,
                  "所提供的迭代器应为随机访问迭代器。");
    // Assert(begin <= end, ExcMessage("数组视图的起始位置应在结束位置之前。"));
    // Assert(internal::is_contiguous(begin, end),
    //        ExcMessage("所提供的范围在内存中并非连续！"));
    // 引用类型（而非值类型）决定了迭代器的 const 属性
    return span<
        typename std::remove_reference<typename std::iterator_traits<Iterator>::reference>::type>(
        std::addressof(*begin), end - begin);
}

/**
 * 由一对指针创建视图。<code>ValueType</code> 可以是 const 限定类型。
 *
 * @warning 指针 @p begin 与 @p end 必须（按通常的半开区间方式）界定一段
 * 内存连续的取值范围。
 *
 * @relatesalso span
 */
template <typename ValueType>
span<ValueType>
make_array_view(ValueType * const begin, ValueType * const end)
{
    // Assert(begin <= end, ExcMessage("数组视图的起始位置应在结束位置之前。"));
    return span<ValueType>(begin, end - begin);
}

/**
 * 由 span 本身创建视图。
 *
 * 本函数用于 @p const 引用的 span 对象，仅出于兼容性目的存在。
 *
 * @param[in] array_view 希望复制的 span。
 *
 * @relatesalso span
 */
template <typename Number>
inline span<const Number>
make_array_view(const span<Number> & array_view)
{
    return make_array_view(array_view.cbegin(), array_view.cend());
}

/**
 * 由 span 本身创建视图。
 *
 * 本函数用于非 @p const 引用的 span 对象，仅出于兼容性目的存在。
 *
 * @param[in] array_view 希望复制的 span。
 *
 * @relatesalso span
 */
template <typename Number>
inline span<Number>
make_array_view(span<Number> & array_view)
{
    return make_array_view(array_view.begin(), array_view.end());
}

/**
 * 为整个 C 风格数组创建视图。这等效于用指向首元素的指针和数组大小
 * 初始化一个 span 对象。
 *
 * 结果 span 是否可写取决于 ValueType 是否为 const 类型。
 *
 * @param[in] array 希望创建 span 的 C 风格数组。span 对应于数组的<em>全部</em>元素。
 *
 * @relatesalso span
 */
template <typename ValueType, int N>
inline span<ValueType>
make_array_view(ValueType (&array)[N])
{
    return span<ValueType>(array, N);
}

/**
 * 为整个 Vector 对象创建视图。这等效于用指向首元素的指针和向量大小
 * 初始化一个 span 对象。
 *
 * 本函数用于非 @p const 引用的 Vector 对象，其元素可写。因此返回类型为
 * 一组可写对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 Vector。数组视图对应于 Vector 的<em>全部</em>元素。
 *
 * @relatesalso span
 */
// template <typename ValueType>
// inline span<ValueType>
// make_array_view(Field<ValueType> & vector)
// {
//     return span<ValueType>(vector.begin(), vector.size());
// }

/**
 * 为整个 Vector 对象创建视图。这等效于用指向首元素的指针和向量大小
 * 初始化一个 span 对象。
 *
 * 本函数用于 @p const 引用的 Vector 对象，其元素不可变。因此返回类型为
 * 一组 @p const 对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 Vector。数组视图对应于 Vector 的<em>全部</em>元素。
 *
 * @relatesalso span
 */
// template <typename ValueType>
// inline span<const ValueType>
// make_array_view(const Field<ValueType> & vector)
// {
//     return span<const ValueType>(vector.begin(), vector.size());
// }

/**
 * 为整个 std::vector 对象创建视图。这等效于用指向首元素的指针和向量大小
 * 初始化一个 span 对象。
 *
 * 本函数用于非 @p const 引用的 vector 对象，其元素可写。因此返回类型为
 * 一组可写对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 vector。数组视图对应于 vector 的<em>全部</em>元素。
 *
 * @relatesalso span
 */
template <typename ValueType>
inline span<ValueType>
make_array_view(std::vector<ValueType> & vector)
{
    return span<ValueType>(vector.data(), vector.size());
}

/**
 * 为整个 std::vector 对象创建视图。这等效于用指向首元素的指针和向量大小
 * 初始化一个 span 对象。
 *
 * 本函数用于 @p const 引用的 vector 对象，其元素不可变。因此返回类型为
 * 一组 @p const 对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 vector。数组视图对应于 vector 的<em>全部</em>元素。
 *
 * @relatesalso span
 */
template <typename ValueType>
inline span<const ValueType>
make_array_view(const std::vector<ValueType> & vector)
{
    return span<const ValueType>(vector.data(), vector.size());
}

/**
 * 为 std::vector 对象的一部分创建视图。这等效于用指向第 @p starting_index
 * 个元素的指针和视图长度 @p size_of_view 初始化 span 对象。
 *
 * 本函数用于非 @p const 引用的 vector 对象，其元素可写。因此返回类型为
 * 一组可写对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 vector。
 * @param[in] starting_index 将纳入本视图的 vector 首元素索引。
 * @param[in] size_of_view 新 span 中的元素个数。
 *
 * @pre <code>starting_index + size_of_view <= vector.size()</code>
 *
 * @relatesalso span
 */
template <typename ValueType>
inline span<ValueType>
make_array_view(std::vector<ValueType> & vector,
                const std::size_t starting_index,
                const std::size_t size_of_view)
{
    // Assert(starting_index + size_of_view <= vector.size(),
    //        ExcMessage("所要创建视图的起始索引与大小将导致视图超出给定 vector 的末尾。"));
    return span<ValueType>(&vector[starting_index], size_of_view);
}

/**
 * 为 std::vector 对象的一部分创建视图。这等效于用指向第 @p starting_index
 * 个元素的指针和视图长度 @p size_of_view 初始化 span 对象。
 *
 * 本函数用于 @p const 引用的 vector 对象，其元素不可变。因此返回类型为
 * 一组 @p const 对象的视图。
 *
 * @param[in] vector 希望创建数组视图的 vector。
 * @param[in] starting_index 将纳入本视图的 vector 首元素索引。
 * @param[in] size_of_view 新 span 中的元素个数。
 *
 * @pre <code>starting_index + size_of_view <= vector.size()</code>
 *
 * @relatesalso span
 */
template <typename ValueType>
inline span<const ValueType>
make_array_view(const std::vector<ValueType> & vector,
                const std::size_t starting_index,
                const std::size_t size_of_view)
{
    // Assert(starting_index + size_of_view <= vector.size(),
    //        ExcMessage("所要创建视图的起始索引与大小将导致视图超出给定 vector 的末尾。"));
    return span<const ValueType>(&vector[starting_index], size_of_view);
}

/*
 * 创建一个不允许修改所指向容器的视图。
 * 当传入的对象尚非 `const` 而函数签名要求常量内存视图时，本函数尤为有用。
 *
 * 本函数返回类型为 `span<const T>` 的对象，其中 `T` 为容器的元素类型。
 *
 * @relatesalso span
 */
template <typename Container>
inline auto
make_const_array_view(const Container & container) -> decltype(make_array_view(container))
{
    return make_array_view(container);
}

} // namespace kp
#else

#include <span>

namespace kp
{

template <typename Type, size_t Extent = static_cast<size_t>(-1)>
using span = std::span<Type, Extent>;

namespace internal
{
// 与非 C++20 分支保持一致的连续性检查（随机访问迭代器）
template <class Iterator>
inline bool
is_contiguous(const Iterator & first, const Iterator & last)
{
    const auto n = std::distance(first, last);
    for (typename std::decay<decltype(n)>::type i = 0; i < n; ++i)
        if (std::addressof(*(std::next(first, i))) != std::next(std::addressof(*first), i))
            return false;
    return true;
}

// 指针范围天然连续
template <class T>
constexpr bool
is_contiguous(T *, T *)
{
    return true;
}
} // namespace internal

// 迭代器范围工厂
template <typename Iterator>
inline std::span<
    typename std::remove_reference<typename std::iterator_traits<Iterator>::reference>::type>
make_array_view(const Iterator begin, const Iterator end)
{
    static_assert(std::is_same<typename std::iterator_traits<Iterator>::iterator_category,
                               typename std::random_access_iterator_tag>::value,
                  "所提供的迭代器应为随机访问迭代器。");
    static_assert(begin <= end, "数组视图的起始位置应在结束位置之前。");
    static_assert(internal::is_contiguous(begin, end), "所提供的范围在内存中并非连续！");
    using Elem =
        typename std::remove_reference<typename std::iterator_traits<Iterator>::reference>::type;
    return std::span<Elem>(std::addressof(*begin), static_cast<std::size_t>(end - begin));
}

// 指针范围工厂
template <typename ValueType>
inline std::span<ValueType>
make_array_view(ValueType * const begin, ValueType * const end)
{
    static_assert(begin <= end, "数组视图的起始位置应在结束位置之前。");
    return std::span<ValueType>(begin, static_cast<std::size_t>(end - begin));
}

// 从 span 生成只读视图
template <typename Number>
inline std::span<const Number>
make_array_view(const std::span<Number> & s)
{
    return std::span<const Number>(s.data(), s.size());
}

// 从 span 生成可写视图
template <typename Number>
inline std::span<Number>
make_array_view(std::span<Number> & s)
{
    return std::span<Number>(s.data(), s.size());
}

// C 数组工厂
template <typename ValueType, int N>
inline std::span<ValueType>
make_array_view(ValueType (&array)[N])
{
    return std::span<ValueType>(array, N);
}

// std::vector 工厂（可写/只读）
template <typename ValueType>
inline std::span<ValueType>
make_array_view(std::vector<ValueType> & v)
{
    return std::span<ValueType>(v.data(), v.size());
}

template <typename ValueType>
inline std::span<const ValueType>
make_array_view(const std::vector<ValueType> & v)
{
    return std::span<const ValueType>(v.data(), v.size());
}

/*
 * 创建一个不允许修改所指向容器的视图。
 * 当传入的对象尚非 `const` 而函数签名要求常量内存视图时，本函数尤为有用。
 *
 * 本函数返回类型为 `span<const T>` 的对象，其中 `T` 为容器的元素类型。
 *
 * @relatesalso span
 */
template <typename Container>
inline auto
make_const_array_view(const Container & container) -> decltype(make_array_view(container))
{
    return make_array_view(container);
}

} // namespace kp

#endif

#endif
